#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include "LockGuard.hpp"
#define NUM 4
using namespace std;

struct ThreadData
{   
    ThreadData(int i) 
    {
        _threadName = "Thread-" + to_string(i);
    }
    string _threadName;
};

// 共享资源，票
int ticket = 1000;

void* GetTicket(void* args)
{
    static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;    // 也可以使用全局变量
    ThreadData* data = static_cast<ThreadData*>(args);
    const char* name = data->_threadName.c_str();
    while(true) {
        {
            LockGuard lockGuard(&lock);
            if(ticket > 0) {
                usleep(1000);
                // 抢票
                printf("%s get a ticket, ticket: %d\n", name, ticket);
                ticket--;
                pthread_mutex_unlock(&lock);
            }
            else {
                // 没票了，该线程就break
                printf("%s can not get ticket, done\n", name);
                pthread_mutex_unlock(&lock);
                break;
            }
        }
        /* 防止这个线程抢完票后又立即去申请锁，让它sleep()一会儿，给其它正在被阻塞的线程一个机会，否则该线程迟迟分配不到资源, 会导致饥饿问题 */
        usleep(15);     
    }
    return nullptr;
}

int main()
{
    vector<pthread_t> tids;
    vector<ThreadData*> datas;
    for(size_t i = 1; i <= NUM; ++i) {
        ThreadData* data = new ThreadData(i);
        datas.push_back(data);
        pthread_t tid;
        pthread_create(&tid, nullptr, GetTicket, datas[i-1]);
        tids.push_back(tid);
    }

    // 善后处理
    for(const auto& t : tids)    pthread_join(t, nullptr);
    for(const auto& d : datas)   delete d;
    return 0;
}

